package com.amigo.online.provider.user.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import com.amigo.online.common.param.dto.PushMessageDto;
import com.amigo.online.common.util.onesignal.PushMessageEnum;
import com.amigo.online.provider.user.figen.MessageFeignService;
import com.amigo.online.provider.user.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.amigo.online.common.base.service.BaseService;
import com.amigo.online.common.core.response.Response;
import com.amigo.online.common.core.response.StatusCode;
import com.amigo.online.common.param.RedisKey;
import com.amigo.online.common.param.dto.user.FollowQueryDto;
import com.amigo.online.common.param.dto.video.VideoQueryDto;
import com.amigo.online.common.param.result.UserInfo;
import com.amigo.online.common.param.result.VideoInfo;
import com.amigo.online.provider.user.common.GlobalController;
import com.amigo.online.provider.user.common.RwRedisService;
import com.amigo.online.provider.user.exception.UserException;
import com.amigo.online.provider.user.mapper.FollowMapper;
import com.amigo.online.provider.user.mapper.UserMapper;
import com.amigo.online.provider.user.model.entity.Follow;
import com.amigo.online.provider.user.util.ConvertUtil;

@Service
@Transactional(rollbackFor = Exception.class)
public class FollowServiceImpl extends BaseService<Follow> implements FollowService {

    Logger log = LoggerFactory.getLogger(FollowServiceImpl.class);

    @Resource
    UserMapper userMapper;

    @Resource
    FollowMapper followMapper;

    @Resource
    RedisService redisService;

    @Resource
    VideoFeignService videoFeignService;
    @Resource
    MessageFeignService messageFeignService;

    @Resource
    private UserService userService;

    // 关注的人
    private static String user_follow_list_key = RedisKey.USER_FOLLOW_REDIS_KEY;
    // 粉丝
    private static String user_fans_list_key = RedisKey.USER_FANS_REDIS_KEY;
    // 用户缓存
    private static String user_List_key = RedisKey.USER_REDIS_KEY;
    // 好友
    private static String user_friends_key = RedisKey.USER_FRIENDS_REDIS_KEY;

    @Autowired
    RwRedisService rwRedisService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 关注用户
     */
    @Override
    public boolean concern(Long userId) {
        UserInfo localUser = GlobalController.getNowUser();
        Long targetUserId = userMapper.selectUserIdById(userId);
        if (targetUserId == null) {
            throw new UserException(StatusCode.BAD_REQUEST);
        }
        if (userId.equals(localUser.getId())) {
            throw new UserException(StatusCode.USER_FOLLOW_WARING);
        }
        // 目标是否是我关注的人
        Follow concernFollow = followMapper.checkConcernSingle(targetUserId, localUser.getId());
        // 目标是否是我粉丝
        Follow fansFollow = followMapper.checkFansSingle(targetUserId, localUser.getId());
        long time = System.currentTimeMillis() / 1000;
        if (null != concernFollow && concernFollow.getCanceled().equals(0)) {
            log.error("关注接口," + localUser.getId() + "已经关注" + userId);
            return true;
        } else {
            if (null == concernFollow) {
                concernFollow = new Follow();
            }
            concernFollow.setUserId(localUser.getId());
            concernFollow.setTargetId(userId);
            concernFollow.setCanceled(0);
            concernFollow.setCreatedTime(time);
        }

        if (null != fansFollow && fansFollow.getCanceled().equals(0)) {
            concernFollow.setMutual(1);
            fansFollow.setMutual(1);
            followMapper.updateByPrimaryKey(fansFollow);
        } else {
            concernFollow.setMutual(0); // 非互相关注（非 好友）
        }
        if (null != concernFollow.getId()) {
            followMapper.updateByPrimaryKey(concernFollow);
        } else {
            followMapper.insert(concernFollow);
        }
        List<Object> results = stringRedisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                StringRedisConnection stringRedisConn = (StringRedisConnection) connection;
                if (null != fansFollow && fansFollow.getCanceled().equals(0)) {
                    // 成为好友后，在缓存中加入这个好友
                    String friends_key1 = user_friends_key + localUser.getId();
                    String friends_key2 = user_friends_key + userId;
                    stringRedisConn.rPush(friends_key1, userId.toString());
                    stringRedisConn.rPush(friends_key2, localUser.getId().toString());
                }
                stringRedisConn.lPush(user_follow_list_key + localUser.getId(), userId.toString());
                stringRedisConn.lPush(user_fans_list_key + userId, localUser.getId().toString());
                return null;
            }
        });
        //发送推送消息
        PushMessageDto pushMessageDto = new PushMessageDto(PushMessageEnum.FOLLOW.getHeading(),PushMessageEnum.FOLLOW.getContents(localUser.getNickname()),new Long[]{userId});
        messageFeignService.pushByOneSignalId(pushMessageDto);
        if (results.size() != 4 && results.size() != 2) {
            log.error("用户:" + localUser.getId() + "关注用户:" + userId + "的缓存队列插入有问题!实际插入" + results.size() + "个");
        }
        return true;
    }

    /**
     * 取消关注
     */
    @Override
    public boolean cancel(Long targetId) {
        UserInfo localUser = GlobalController.getNowUser();
        Long targetUserId = userMapper.selectUserIdById(targetId);
        if (targetUserId == null) {
            throw new UserException(StatusCode.BAD_REQUEST);
        }
        // 目标是否是我关注的人
        Follow concernFollow = followMapper.checkConcernSingle(targetUserId, localUser.getId());
        // 目标是否是我粉丝
        Follow fansFollow = followMapper.checkFansSingle(targetUserId, localUser.getId());
        if (null == concernFollow || concernFollow.getCanceled().equals(1)) {
            log.error("取消关注接口," + localUser.getId() + "没有关注" + targetId);
            return true;
        }
        long time = System.currentTimeMillis() / 1000;
        concernFollow.setCanceled(1);
        concernFollow.setCanceledTime(time);
        concernFollow.setUserId(localUser.getId());
        concernFollow.setTargetId(targetId);
        concernFollow.setMutual(0);
        followMapper.updateCanceled(concernFollow);
        if (fansFollow != null && fansFollow.getCanceled().equals(0)) {
            fansFollow.setMutual(0);
            followMapper.updateByPrimaryKey(fansFollow);
        }
        /**
         * 更新缓存
         */
        List<Object> results = stringRedisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {

                StringRedisConnection stringRedisConn = (StringRedisConnection) connection;
                if (fansFollow != null && fansFollow.getCanceled().equals(0)) {
                    // 取消关注后，更新这2个用户的好友列表以及关注者和粉丝缓存
                    String friends_key1 = user_friends_key + localUser.getId();
                    String friends_key2 = user_friends_key + targetId;
                    stringRedisConn.lRem(friends_key1, 0, targetId.toString());
                    stringRedisConn.lRem(friends_key2, 0, localUser.getId().toString());
                }

                stringRedisConn.lRem(user_follow_list_key + localUser.getId(), 0, targetId.toString());
                stringRedisConn.lRem(user_fans_list_key + targetId, 0, localUser.getId().toString());
                return null;
            }
        });
        if (results.size() != 4 && results.size() != 2) {
            log.error("用户:" + localUser.getId() + "取消关注用户:" + targetId + "的缓存队列移除有问题!实际删数据" + results.size() + "个");
        }
        return true;
    }

    /**
     * 获取粉丝列表
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<UserInfo> getFansById(Long id, Integer page, Integer size) {
		/*UserInfo localUserInfo = GlobalController.getNowUser();
		
		int startIndex = (page - 1) * size;
		
		int endIndex = page * size - 1;
		
		List<UserInfo> resultList = new ArrayList<>(size);
				
		List<Object> fansList = rwRedisService.opsForListRead().range(RedisKey.USER_FANS_REDIS_KEY, startIndex, endIndex);
		
		if(fansList.size() != 0) {	
			resultList = (List<UserInfo>) (List<?>) rwRedisService.opsForHashRead().multiGet(RedisKey.USER_REDIS_KEY, fansList);
		    //List<Long> list2 = rwRedisService.opsForHashRead().multiGet(user_List_key, fansList);		
		} else {
			List<Long> allFansIdList = followMapper.listFindUserFansByUserId(localUserInfo.getId());
			if(allFansIdList.size() != 0) {
				rwRedisService.opsForList().rightPush(RedisKey.USER_FANS_REDIS_KEY, allFansIdList);
				if(allFansIdList.size() >= startIndex) {
					List<Long> resultfansIds = allFansIdList.subList(startIndex, endIndex);
					resultList = ConvertUtil.UsersToUserInfos(userMapper.findByIdList(resultfansIds));
				}				
			}			
		}
		return resultList;*/
        // 获取查询起始下标
        Integer i_offset = (page - 1) * size;
        Response r = new Response();
        // 调用redis公共查询方法
        List<Object> list = (List<Object>) redisService.listFromRedis(page, size,
                user_fans_list_key + id, user_List_key, r);
        int res = Integer.parseInt(r.getData().toString());
        if (res == 0) {
            return (List<UserInfo>) (List<?>) list;
        } else {
            List<Long> fansList = null;
            // 第一步失败，查mysql获取fansList
            if (res == 1) {
                /**
                 * 先查询1000个清除缓存，然后塞进缓存
                 */
                FollowQueryDto followQueryDto = new FollowQueryDto();
                followQueryDto.setUserId(id);
                followQueryDto.setLimit(1000);
                followQueryDto.setOffset(0L);
                List<Long> fansList_temp = followMapper.selectFansId(followQueryDto);
                redisService.deleteKey(user_fans_list_key + id);
                // listOperations.leftPush(user_fans_list_key+u.getId(), fansList_temp);
                for (int i = 0; i < fansList_temp.size(); i++) {
                    rwRedisService.opsForList().rightPush(user_fans_list_key + id, fansList_temp.get(i));
                }
                Long offset = Long.valueOf(i_offset.toString());
                followQueryDto.setLimit(size);
                followQueryDto.setOffset(offset);
                fansList = followMapper.selectFansId(followQueryDto);

            }
            // 第二步失败，直接使用redis里的fansList
            if (res == 2) {
                fansList = (List<Long>) (List<?>) list;
            }
            if (fansList == null || fansList.size() <= 0) {
                return null;
            }
            // 无论第几步失败，userInfo都是根据fansList查询数据库获取
            List<UserInfo> sqUserInfoList = ConvertUtil.UsersToUserInfos(userMapper.findByIdList(fansList));
            for (UserInfo userInfo : sqUserInfoList) {
                rwRedisService.opsForHash().put(user_List_key, userInfo.getId(), userInfo);
            }
            return sqUserInfoList;
        }
    }

    /**
     * 获取关注的人的列表
     */
    @Override
    public List<UserInfo> getConcernById(Long id, Integer page, Integer size) {
        Integer i_offset = (page - 1) * size;
        Response r = new Response();
        // 调用redis公共查询方法
        List<Object> list = (List<Object>) redisService.listFromRedis(page, size, user_follow_list_key + id,
                user_List_key, r);
        int res = Integer.parseInt(r.getData().toString());
        if (res == 0) {
            return (List<UserInfo>) (List<?>) list;
        } else {
            List<Long> followList = null;
            // 第一步失败，查mysql获取followList
            if (res == 1) {
                FollowQueryDto followQueryDto = new FollowQueryDto();
                followQueryDto.setUserId(id);
                followQueryDto.setLimit(1000);
                followQueryDto.setOffset(0L);
                List<Long> followList_temp = followMapper.selectConcernId(followQueryDto);
                redisService.deleteKey(user_follow_list_key + id);
                for (int i = 0; i < followList_temp.size(); i++) {
                    rwRedisService.opsForList().rightPush(user_follow_list_key + id, followList_temp.get(i));
                }
                Long offset = Long.valueOf(i_offset.toString());
                followQueryDto.setLimit(size);
                followQueryDto.setOffset(offset);
                followList = followMapper.selectConcernId(followQueryDto);
            }

            if (res == 2) {
                followList = (List<Long>) (List<?>) list;
            }
            if (followList == null || followList.size() <= 0) {
                return null;
            }
            // 无论第几步失败，userInfo都是根据followList查询数据库获取
            List<UserInfo> sqUserInfoList = ConvertUtil.UsersToUserInfos(userMapper.findByIdList(followList));
            for (UserInfo userInfo : sqUserInfoList) {
                rwRedisService.opsForHash().put(user_List_key, userInfo.getId(), userInfo);
            }
            return sqUserInfoList;
        }
    }

    /**
     * 获取我关注的人的视频
     */
    @Override
    public List<VideoInfo> getMyConcernVideos(Integer page, Integer size) {
        UserInfo u = GlobalController.getNowUser();
        // 查询关注的所有人的Id
        List<Object> followList = rwRedisService.lrange(user_follow_list_key + u.getId(), 0, -1);
        List<Long> concren_id = new ArrayList<Long>();
        if (followList == null || followList.size() < size) {
            FollowQueryDto followQueryDto = new FollowQueryDto();
            followQueryDto.setUserId(u.getId());
            followQueryDto.setOffset(0L);
            followQueryDto.setLimit(1000);
            concren_id = followMapper.selectConcernId(followQueryDto);
            if (concren_id == null || concren_id.size() <= 0) {
                return null;
            } else {
                redisService.deleteKey(user_follow_list_key + u.getId());
                for (int i = 0; i < concren_id.size(); i++) {
                    rwRedisService.opsForList().rightPush(user_follow_list_key + u.getId(), concren_id.get(i));
                }
            }
        } else {
            for (Object o : followList) {
                concren_id.add(Long.valueOf(String.valueOf(o)));
            }
        }
        Integer i_offset = (page - 1) * size;
        Long offset = Long.valueOf(i_offset.toString());
        VideoQueryDto dto = new VideoQueryDto();
        dto.setUserIdList(concren_id);
        dto.setLimit(size);
        dto.setOffset(offset);
        dto.setUserId(0L);
        ResponseEntity<Response> response = videoFeignService.getVideoInfoByUserIdList(dto);
        List<VideoInfo> videoInfoList = (List<VideoInfo>) response.getBody().getData();
        return videoInfoList;
    }

    /**
     * 获取好友列表
     *
     * @return
     */
    @Override
    public List<UserInfo> getFriends() {
        UserInfo localUser = GlobalController.getNowUser();
        Response r = new Response();
        // 调用redis公共查询方法
        List<Object> list = (List<Object>) redisService.listFromRedis(null, null, user_friends_key + localUser.getId(),
                user_List_key, r);
        int res = Integer.parseInt(r.getData().toString());
        if (res == 0) {
            return (List<UserInfo>) (List<?>) list;
        } else {
            List<Long> firendsList = null;
            // 第一步失败，查mysql获取
            if (res == 1) {
                firendsList = followMapper.getFriendsId(localUser.getId());
                redisService.deleteKey(user_friends_key + localUser.getId());
                // listOperations.rightPush(user_friends_key+u.getId(), firendsList);
                for (int i = 0; i < firendsList.size(); i++) {
                    rwRedisService.opsForList().rightPush(user_friends_key + localUser.getId(), firendsList.get(i));
                }
            }
            if (res == 2) {
                firendsList = (List<Long>) (List<?>) list;
            }
            if (firendsList == null || firendsList.size() <= 0) {
                return null;
            }
            // 无论第几步失败，userInfo都是根据firendsList查询数据库获取
            List<UserInfo> sqUserInfoList = ConvertUtil.UsersToUserInfos(userMapper.findByIdList(firendsList));
            for (UserInfo userInfo : sqUserInfoList) {
                rwRedisService.opsForHash().put(user_List_key, userInfo.getId(), userInfo);
            }
            // return userInfoToSimpleUserInfo(sqUserInfoList);
            return sqUserInfoList;
        }
    }

    @Override
    public List<Long> findFollowStateByUserIdAndUserIds(Long id, List<Long> ids) {
        List<Long> userids = new ArrayList<>();
        if (ids != null && ids.size() != 0) {
            userids = followMapper.findFollowStateByUserIdAndUserIds(id, ids);
        }
        return userids;
    }

    @Override
    public boolean checkIsFriend(long localUserid, long otherUserid) {
        List<Object> friendList = rwRedisService.lrange(user_friends_key + localUserid, 0, -1);
        boolean result = false;
        for (Object obj : friendList) {
            if (((Integer) obj).equals(Long.valueOf(otherUserid).intValue())) {
                result = true;
                break;
            }
        }
        return result;
    }

    @Override
    public List<Boolean> checkIsFriends(long localUserid, List<Long> otherUserids) {
        return null;
    }

}
